﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.PanGu;
using System.IO;
using Lucene.Net.Store;
using Lucene.Net.Index;
using Lucene.Net.Documents;
using PanGu;
using PanGu.HighLight;
using Lucene.Net.Search;
using Lucene.Net.QueryParsers;

namespace Chinaer.LuceneNet
{
    public class SearchHelper
    {
        /// <summary>
        /// 分词
        /// </summary>
        /// <param name="word">要分的词</param>
        /// <returns>string数组:分好的词的集合</returns>
        public string[] SplitWords(string word)
        {
            //创建列表，用来装分好的词
            List<string> list = new List<string>();

            //实例化一个PanGuAnalyzer对象
            Analyzer analyzer = new PanGuAnalyzer();

            //然后通过分析器得到一个TokenStream
            TokenStream tokenStream = analyzer.TokenStream("", new StringReader(word));

            Lucene.Net.Analysis.Token token;
            //遍历tokenStream中的Token，如果为空返回Null
            while ((token = tokenStream.Next()) != null)
            {
                //将每一个分词添加到list中
                list.Add(token.TermText());
            }

            return list.ToArray();
        }

        /// <summary>
        /// 创建索引   原则是定期的创建索引  利用定时器
        /// </summary>
        public void CreateIndex()
        {
            string indexPath = IndexDic;
            if (string.IsNullOrEmpty(indexPath))
            {
                indexPath = "d:/index/";
            }
            try
            {
                if (!System.IO.Directory.Exists(indexPath))
                {
                    System.IO.Directory.CreateDirectory(indexPath);
                }
            }
            catch (Exception ex)
            {
                Chinaer.Core.Helper.LogHelper.Instance.WriteLog("SearchHelper", "", Chinaer.Core.Helper.ExceptionMessageHelper.RollException(ex));
                Chinaer.Core.Helper.ExceptonHelper.ThrowException(ex.Message);
            }


            FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());
            ///检查目录是否存在
            bool isUpdate = IndexReader.IndexExists(directory);
            if (isUpdate)
            {
                //目录存在则要判断是否锁定
                if (IndexWriter.IsLocked(directory))
                {
                    IndexWriter.Unlock(directory);
                }
            }
            ///IndexWriter主要用于写入索引 第三个参数是表示是否创建目录
            ///第四个参数是表示的最大长度
            IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, IndexWriter.MaxFieldLength.UNLIMITED);
            //索引三个字段 ID Name Description
            Bll.MenuDeatil menuDetail = new Bll.MenuDeatil();

            foreach (var item in menuDetail.GetAllMenuDetail())
            {
                writer.DeleteDocuments(new Term("id", item.ID));
                //Document文档对象
                Document document = new Document();
                //将获取到的内容写入索引中
                document.Add(new Field("id", item.ID, Field.Store.YES, Field.Index.NOT_ANALYZED));

                document.Add(new Field("title", item.Name, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));

                document.Add(new Field("description", item.MenuDetailDescription, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));

                document.Add(new Field("addtime", item.CreateTime.ToString(), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
                writer.AddDocument(document);
            }
            ///关闭writer
            writer.Optimize();//进行优化
            writer.Close();
            directory.Close();
        }
        #region 从索引搜索结果
        /// <summary>
        /// 从索引搜索结果
        /// </summary>
        public List<DTO.MenuDetailDTO> SearchIndex(string Words, int PageSize, int PageIndex, out int _totalcount)
        {
            _totalcount = 0;
            Dictionary<string, string> dic = new Dictionary<string, string>();
            BooleanQuery bQuery = new BooleanQuery();
            string title = string.Empty;
            string description = string.Empty;
            string Addtime = DateTime.Now.ToString();
            title = GetKeyWordsSplitBySpace(Words);
            QueryParser parse = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, "title", new PanGuAnalyzer());
            Query query = parse.Parse(title);
            parse.SetDefaultOperator(QueryParser.Operator.AND);
            bQuery.Add(query, BooleanClause.Occur.SHOULD);
            dic.Add("title", Words);

            description = GetKeyWordsSplitBySpace(Words);
            QueryParser parseC = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, "description", new PanGuAnalyzer());
            Query queryC = parseC.Parse(description);
            parseC.SetDefaultOperator(QueryParser.Operator.AND);
            bQuery.Add(queryC, BooleanClause.Occur.SHOULD);
            dic.Add("description", Words);


            if (bQuery != null && bQuery.GetClauses().Length > 0)
            {
                return GetSearchResult(bQuery, dic, PageSize, PageIndex, out _totalcount);
            }
            return null;
        }
        /// <summary>
        /// 获取  从第一页开始计算
        /// </summary>
        /// <param name="bQuery"></param>
        private List<DTO.MenuDetailDTO> GetSearchResult(BooleanQuery bQuery, Dictionary<string, string> dicKeywords, int PageSize, int PageIndex, out int totalCount)
        {
            List<DTO.MenuDetailDTO> list = new List<DTO.MenuDetailDTO>();
            FSDirectory directory = FSDirectory.Open(new DirectoryInfo(IndexDic), new NoLockFactory());
            IndexReader reader = IndexReader.Open(directory, true);
            IndexSearcher searcher = new IndexSearcher(reader);
            TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);
            Sort sort = new Sort(new SortField("addtime", SortField.DOC, true));
            searcher.Search(bQuery, null, collector);
            totalCount = collector.GetTotalHits();//返回总条数
            TopDocs docs = searcher.Search(bQuery, (Filter)null, PageSize * PageIndex, sort);
            if (docs != null && docs.totalHits > 0)
            {
                for (int i = 0; i < docs.totalHits; i++)
                {
                    if (i >= (PageIndex - 1) * PageSize && i < PageIndex * PageSize)
                    {
                        Document doc = searcher.Doc(docs.scoreDocs[i].doc);
                        DTO.MenuDetailDTO menuDetailDTO = new DTO.MenuDetailDTO()
                        {
                            ID = doc.Get("id").ToString(),
                            Name = doc.Get("title").ToString(),
                            MenuDetailDescription = doc.Get("description").ToString(),
                            CreateTime = DateTime.Parse(doc.Get("addtime").ToString())
                        };
                        list.Add(SetHighlighter(dicKeywords, menuDetailDTO));
                    }
                }
            }
            return list;
        }
        /// <summary>
        /// 设置关键字高亮
        /// </summary>
        /// <param name="dicKeywords">关键字列表</param>
        /// <param name="model">返回的数据模型</param>
        /// <returns></returns>
        private DTO.MenuDetailDTO SetHighlighter(Dictionary<string, string> dicKeywords, DTO.MenuDetailDTO menuDetailDTO)
        {
            SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color=\"red\">", "</font>");
            Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new Segment());
            highlighter.FragmentSize = 250;
            string strTitle = string.Empty;
            string strContent = string.Empty;
            dicKeywords.TryGetValue("title", out strTitle);
            dicKeywords.TryGetValue("description", out strContent);
            if (!string.IsNullOrEmpty(strTitle))
            {
                string title = menuDetailDTO.Name;
                menuDetailDTO.Name = highlighter.GetBestFragment(strTitle, menuDetailDTO.Name);
                if (string.IsNullOrEmpty(menuDetailDTO.Name))
                {
                    menuDetailDTO.Name = title;
                }
            }
            if (!string.IsNullOrEmpty(strContent))
            {
                string content = menuDetailDTO.MenuDetailDescription;
                menuDetailDTO.MenuDetailDescription = highlighter.GetBestFragment(strContent, menuDetailDTO.MenuDetailDescription);
                if (string.IsNullOrEmpty(menuDetailDTO.MenuDetailDescription))
                {
                    menuDetailDTO.MenuDetailDescription = content;
                }
            }
            return menuDetailDTO;
        }
        /// <summary>
        /// 处理关键字为索引格式
        /// </summary>
        /// <param name="keywords"></param>
        /// <returns></returns>
        private string GetKeyWordsSplitBySpace(string keywords)
        {
            PanGuTokenizer ktTokenizer = new PanGuTokenizer();
            StringBuilder result = new StringBuilder();
            ICollection<WordInfo> words = ktTokenizer.SegmentToWordInfos(keywords);
            foreach (WordInfo word in words)
            {
                if (word == null)
                {
                    continue;
                }
                result.AppendFormat("{0}^{1}.0 ", word.Word, (int)Math.Pow(3, word.Rank));
            }
            return result.ToString().Trim();
        }
        #endregion
        /// <summary>
        /// 索引存放目录
        /// </summary>
        protected string IndexDic
        {
            get
            {
                return Chinaer.Core.Helper.ConfigHelper.GetAppSetting("indexDir");
            }
        }
        /// <summary>
        /// 盘古分词配置目录
        /// </summary>
        protected string PanGuPath
        {
            get
            {
                return Chinaer.Core.Helper.ConfigHelper.GetAppSetting("panGuPath");
            }
        }
    }
}
